unit FormMain;
                                                            
interface                                              

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Voxel_Engine, Menus, ExtCtrls, StdCtrls, Voxel, ComCtrls, ToolWin,
  ImgList, Math, palette, Buttons, ogl3dview_engine, OpenGL15,
  ShellAPI, Constants,
  Debug, Normals, VectorTypes, Cursors,
  FormHeaderUnit,LoadForm,FormNewSectionSizeUnit,FormPalettePackAbout,HVA,FormReplaceColor,FormVoxelTexture,
  FormImportSection,FormFullResize,FormVxlError,
  FormResizeVoxelSection, FormInputVector, FormVectorInfo, NormalRoutines,
  FormNewVoxel, FormOGL3dPreview, FormDrawSimple3DObject, ModelView;

type
  TPointProc = procedure(X, Y: Integer) of object;

  TFrmMain = class(TForm)
    MainMenu: TMainMenu;
    File1: TMenuItem;
    Open1: TMenuItem;
    OpenVXLDialog: TOpenDialog;
    Panel1: TPanel;
    LeftPanel: TPanel;
    RightPanel: TPanel;
    MiddlePanel: TPanel;
    ViewCanvas2: TPaintBox;
    ViewLabel1: TLabel;
    ViewLabel2: TLabel;
    ViewLabel0: TLabel;
    View1: TMenuItem;
    ViewMode1: TMenuItem;
    CrossSection1: TMenuItem;
    EmphasiseDepth1: TMenuItem;
    ToolBarImageList: TImageList;
    pnlPalette: TPanel;
    lblActiveColor: TLabel;
    MainViewScrollV: TScrollBar;
    Panel5: TPanel;
    MainViewScrollH: TScrollBar;
    ShowUsedColorsNormals1: TMenuItem;
    ColorDialog: TColorDialog;
    StatusBar: TStatusBar;
    mnuDirectionPopup: TPopupMenu;
    New1: TMenuItem;
    ReOpen1: TMenuItem;
    N1: TMenuItem;
    Save1: TMenuItem;
    SaveAs1: TMenuItem;
    Properties1: TMenuItem;
    N7: TMenuItem;
    N8: TMenuItem;
    Exit1: TMenuItem;
    Section1: TMenuItem;
    SectionHeader1: TMenuItem;
    SaveVXLDialog: TSaveDialog;
    New2: TMenuItem;
    N9: TMenuItem;
    Resize1: TMenuItem;
    Delete1: TMenuItem;
    ClearLayer1: TMenuItem;
    ClearEntireSection1: TMenuItem;
    normalsaphere1: TMenuItem;
    N10: TMenuItem;
    Edit1: TMenuItem;
    Undo1: TMenuItem;
    Redo1: TMenuItem;
    N11: TMenuItem;
    ViewCanvas0: TPaintBox;
    Options1: TMenuItem;
    Section2: TMenuItem;
    Copyofthissection1: TMenuItem;
    Importfrommodel1: TMenuItem;
    Flip1: TMenuItem;
    N15: TMenuItem;
    Mirror1: TMenuItem;
    Nudge1: TMenuItem;
    FlipX1: TMenuItem;
    FlipY1: TMenuItem;
    FlipZ1: TMenuItem;
    MirrorBottomToTop1: TMenuItem;
    MirrorTopToBottom1: TMenuItem;
    N16: TMenuItem;
    MirrorLeftToRight1: TMenuItem;
    MirrorRightToLeft1: TMenuItem;
    N17: TMenuItem;
    MirrorBackToFront1: TMenuItem;
    Nudge1Left1: TMenuItem;
    Nudge1Right1: TMenuItem;
    Nudge1up1: TMenuItem;
    Nudge1Down1: TMenuItem;
    Palette1: TMenuItem;
    RedAlert2Palette1: TMenuItem;
    ClearVoxelColor1: TMenuItem;
    Copy1: TMenuItem;
    Cut1: TMenuItem;
    IconList: TImageList;
    PasteFull1: TMenuItem;
    Paste1: TMenuItem;
    N22: TMenuItem;
    OpenHVADialog: TOpenDialog;
    ReplaceColors1: TMenuItem;
    VoxelTexture1: TMenuItem;
    MirrorFrontToBack2: TMenuItem;
    grpSection: TGroupBox;
    SectionCombo: TComboBox;
    grpTools: TGroupBox;
    btnPencilTool: TSpeedButton;
    btnLineTool: TSpeedButton;
    btnRectTool: TSpeedButton;
    btnFillRectTool: TSpeedButton;
    btnFloodFillTool: TSpeedButton;
    btnToggleCN: TSpeedButton;
    grpLayers: TGroupBox;
    lblLayerX: TLabel;
    lblLayerY: TLabel;
    lblLayerZ: TLabel;
    XCursorTrackBar: TTrackBar;
    YCursorTrackBar: TTrackBar;
    ZCursorTrackBar: TTrackBar;
    pnlActiveColor: TPanel;
    pnlInfo: TPanel;
    TiberianSunPalette1: TMenuItem;
    btnFloodFill3DTool: TSpeedButton;
    RemoveRedundantVoxels2: TMenuItem;
    Splitter1: TSplitter;
    Splitter2: TSplitter;
    Enable3DView1: TMenuItem;
    cnvPalette: TPaintBox;
    Panel2: TPanel;
    btnShowNormalInfo: TButton;
    btnNormalPenTool: TSpeedButton;
    AutoNormals11: TMenuItem;
    ZoomEditingViewToFit1: TMenuItem;
    CanvasContainer0: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Top2: TMenuItem;
    Right2: TMenuItem;
    Front2: TMenuItem;
    Bottom2: TMenuItem;
    Left2: TMenuItem;
    Back2: TMenuItem;
    Tools1: TMenuItem;
    btnFindNormal: TButton;
    Panel6: TPanel;
    Button1: TButton;
    Popup3d: TPopupMenu;
    Views1: TMenuItem;
    Front1: TMenuItem;
    Back1: TMenuItem;
    MenuItem1: TMenuItem;
    LEft1: TMenuItem;
    Right1: TMenuItem;
    MenuItem2: TMenuItem;
    Bottom1: TMenuItem;
    op1: TMenuItem;
    N3: TMenuItem;
    Cameo1: TMenuItem;
    Cameo21: TMenuItem;
    Cameo31: TMenuItem;
    Cameo41: TMenuItem;
    RemapColor1: TMenuItem;
    Gold1: TMenuItem;
    Red1: TMenuItem;
    Orange1: TMenuItem;
    Magenta1: TMenuItem;
    Purple1: TMenuItem;
    Blue1: TMenuItem;
    Green1: TMenuItem;
    DarkSky1: TMenuItem;
    White1: TMenuItem;
    N5: TMenuItem;
    Options2: TMenuItem;
    DebugMode1: TMenuItem;
    Disable3dView1: TMenuItem;
    N4: TMenuItem;
    BackgroundColor1: TMenuItem;
    TextColor1: TMenuItem;
    BackgroundColor2: TMenuItem;
    CanvasContainer1: TPanel;
    ViewCanvas1: TPaintBox;
    CanvasContainer2: TPanel;
    btnEllipseTool: TSpeedButton;
    btnFillEllipseTool: TSpeedButton;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Open1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure changecaption(Filename : boolean; FName : string);
    Procedure SetEditable(Value : boolean);
    Procedure SetupSections;
    procedure SectionComboChange(Sender: TObject);
    Procedure SetSpectrum(Mode: ESpectrumMode);
    procedure cnvPalettePaint(Sender: TObject);
    procedure SetActiveColor(Index: Integer; UpdateUI: boolean);
    procedure SetActiveNormal(Index: Integer; UpdateUI: boolean);
    Procedure UpdateColorNormalInfo(Value : integer);
    procedure FormShow(Sender: TObject);
    procedure cnvPaletteMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ShowUsedColorsNormals1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure OGL3DPreviewMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure OGL3DPreviewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure OGL3DPreviewMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure OGL3DPreviewMouseWheelUp(Sender: TObject;
      Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure OGL3DPreviewMouseWheelDown(Sender: TObject;
      Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure OGL3DPreviewResize(Sender: TObject);
    procedure OGL3DPreviewPaint(Sender: TObject);
    procedure OGL3DPreviewClose(Sender: TObject; var Action: TCloseAction);
    procedure SpeedButton2Click(Sender: TObject);
    procedure BackgroundColor1Click(Sender: TObject);
    procedure TextColor1Click(Sender: TObject);
    procedure Gold1Click(Sender: TObject);
    procedure Red1Click(Sender: TObject);
    procedure Orange1Click(Sender: TObject);
    procedure Magenta1Click(Sender: TObject);
    procedure Purple1Click(Sender: TObject);
    procedure Blue1Click(Sender: TObject);
    procedure Green1Click(Sender: TObject);
    procedure DarkSky1Click(Sender: TObject);
    procedure White1Click(Sender: TObject);
    procedure Front1Click(Sender: TObject);
    procedure Back1Click(Sender: TObject);
    procedure LEft1Click(Sender: TObject);
    procedure Right1Click(Sender: TObject);
    procedure Bottom1Click(Sender: TObject);
    procedure op1Click(Sender: TObject);
    procedure Cameo1Click(Sender: TObject);
    procedure Cameo21Click(Sender: TObject);
    procedure Cameo31Click(Sender: TObject);
    procedure Cameo41Click(Sender: TObject);
    Procedure ChangeFocus(X, Y, Z: Integer; Repaint: Boolean);
    procedure XCursorTrackBarChange(Sender: TObject);
    Procedure CursorReset;
    Procedure SetupStatusBar;
    procedure mnuEditClick(Sender: TObject);
    procedure PostLoad;
    Procedure SetVXLTool(VXLToolID : Integer);
    procedure btnLineToolClick(Sender: TObject);
    procedure btnFloodFillToolClick(Sender: TObject);
    procedure btnRectToolClick(Sender: TObject);
    procedure btnFillRectToolClick(Sender: TObject);
    procedure btnEllipseToolClick(Sender: TObject);
    procedure btnFillEllipseToolClick(Sender: TObject);
    procedure Save1Click(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure SaveAs1Click(Sender: TObject);
    procedure SectionHeader1Click(Sender: TObject);
    procedure Properties1Click(Sender: TObject);
    procedure Delete1Click(Sender: TObject);
    procedure normalsaphere1Click(Sender: TObject);
    procedure ClearEntireSection1Click(Sender: TObject);
    procedure VXLSEHelp1Click(Sender: TObject);
    procedure Section2Click(Sender: TObject);
    procedure Copyofthissection1Click(Sender: TObject);
    procedure mnuHistoryClick(Sender: TObject);
    procedure TiberianSunPalette1Click(Sender: TObject);
    procedure RedAlert2Palette1Click(Sender: TObject);
    procedure blank1Click(Sender: TObject);
    Function SaveFileQuery : Boolean;
    procedure ClearVoxelColorToolBtnClick(Sender: TObject);
    procedure VoxelTexture1Click(Sender: TObject);

    procedure Importfrommodel1Click(Sender: TObject);
    procedure Resize1Click(Sender: TObject);
    procedure YCursorSpinBtnUpClick(Sender: TObject);
    procedure YCursorSpinBtnDownClick(Sender: TObject);
    procedure ZCursorSpinBtnDownClick(Sender: TObject);
    procedure ZCursorSpinBtnUpClick(Sender: TObject);
    procedure XCursorSpinBtnDownClick(Sender: TObject);
    procedure XCursorSpinBtnUpClick(Sender: TObject);
    procedure btnToggleCNClick(Sender: TObject);
    Procedure CreateVxlError(v,n : Boolean);
    procedure UpdateFocusInfo;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure btnPencilToolClick(Sender: TObject);
    procedure btnFindNormalClick(Sender: TObject);
    procedure btnShowNormalInfoClick(Sender: TObject);
    procedure New1Click(Sender: TObject);
    procedure btnFloodFill3DToolClick(Sender: TObject);
    procedure RemoveRedundantVoxels2Click(Sender: TObject);
    procedure Enable3DView1Click(Sender: TObject);
    procedure AutoNormals11Click(Sender: TObject);
    procedure ReplaceColors1Click(Sender: TObject);
    procedure ViewCanvas0Paint(Sender: TObject);
    procedure ViewCanvas1Paint(Sender: TObject);
    procedure ViewCanvas2Paint(Sender: TObject);
    procedure ZoomEditingViewToFit1Click(Sender: TObject);
    procedure ViewLabel1Click(Sender: TObject);
    procedure ViewLabel2Click(Sender: TObject);
    procedure CrossSection1Click(Sender: TObject);
    procedure EmphasiseDepth1Click(Sender: TObject);
    procedure ViewCanvas0MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ViewCanvas0MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ViewCanvas0MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure BackgroundColor2Click(Sender: TObject);
    procedure ViewCanvas1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ViewCanvas2MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure CanvasContainer1Resize(Sender: TObject);
    procedure CanvasContainer2Resize(Sender: TObject);
    procedure CanvasContainer0Resize(Sender: TObject);
    procedure ViewCanvas1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ViewCanvas2MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    Editable: Boolean;
    Enabled3DView: Boolean;

    LastViewCoords: array [0..2] of TPoint;

    ViewLabels: array[0..2] of TLabel;
    ViewCanvas: array[0..2] of TPaintBox;
    CanvasContainers: array[0..2] of TPanel;

    FrmOGL3dPreview: TFrmOGL3dPreview;
    FrmInputVector: TFrmInputVector;
    InfoForm: TForm;

    PaintingToolProcMouseDown: array[0..VxlToolCount-1] of TPointProc;
    PaintingToolProcMouseMove: array[0..VxlToolCount-1] of TPointProc;
    PaintingToolProcMouseUp:   array[0..VxlToolCount-1] of TPointProc;

    ModelViews: array[0..2] of TModelView;

    MouseDownLeft: Boolean;
    MouseDownRight: Boolean;

    procedure DrawLine(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
    procedure DrawFrameRect(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
    procedure DrawFilledRect(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
    procedure DrawFrameEllipse(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
    procedure DrawFilledEllipse(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);

    procedure PaintPointView(X, Y: Integer);
    procedure ClearPointView(X, Y: Integer);
    procedure RepaintPointView(X, Y: Integer);
    procedure PaintPointModel(X, Y: Integer);
    procedure ClearPointModel(X, Y: Integer);

    procedure NullToolProc(X, Y: Integer);
    procedure PencilToolMouseDownMove(X, Y: Integer);
    procedure PencilToolMouseUp(X, Y: Integer);
    procedure LineToolMouseDown(X, Y: Integer);
    procedure LineToolMouseMove(X, Y: Integer);
    procedure LineToolMouseUp(X, Y: Integer);
    procedure FrameRectToolMouseMove(X, Y: Integer);
    procedure FrameRectToolMouseUp(X, Y: Integer);
    procedure FrameEllipseToolMouseMove(X, Y: Integer);
    procedure FrameEllipseToolMouseUp(X, Y: Integer);
    procedure FillRectToolMouseMove(X, Y: Integer);
    procedure FillRectToolMouseUp(X, Y: Integer);
    procedure FillEllipseToolMouseMove(X, Y: Integer);
    procedure FillEllipseToolMouseUp(X, Y: Integer);
    procedure FloodFillToolMouseDown(X, Y: Integer);
    procedure FloodFill3DToolMouseDown(X, Y: Integer);

    procedure InitViews;
    
    procedure SetEnabled3DView(Enabled: Boolean);

    procedure LabelPrimaryView(Orient: EModelViewOrient);
    procedure LabelSecondaryView(Id: Integer; Orient: EModelViewOrient);
    procedure ZoomViewToFit(Id: Integer);
    procedure AdjustViewCanvas(Id: Integer);

  public
    OGL3DPreview: TPaintBox;

    procedure Repaint2DViews;
    procedure Repaint3DView;
    procedure RepaintAllViews;

  end;

var
  FrmMain: TFrmMain;

implementation

{$R *.dfm}

procedure RunAProgram (const theProgram, itsParameters, defaultDirectory : string);
var rslt     : integer;
    msg      : string;
begin
rslt := ShellExecute (0, 'open',
                        pChar (theProgram),
                        pChar (itsParameters),
                        pChar (defaultDirectory),
                        sw_ShowNormal);
if rslt <= 32
then begin
     case rslt of
          0,
          se_err_OOM :             msg := 'Out of memory/resources';
          error_File_Not_Found :   msg := 'File "' + theProgram + '" not found';
          error_Path_Not_Found :   msg := 'Path not found';
          error_Bad_Format :       msg := 'Damaged or invalid exe';
          se_err_AccessDenied :    msg := 'Access denied';
          se_err_NoAssoc,
          se_err_AssocIncomplete : msg := 'Filename association invalid';
          se_err_DDEBusy,
          se_err_DDEFail,
          se_err_DDETimeOut :      msg := 'DDE error';
         se_err_Share :        msg := 'Sharing violation';
          else                    msg := 'no text';
          end; // of case
     raise Exception.Create ('ShellExecute error #' + IntToStr (rslt) + ': ' + msg);
     end;
end;

procedure TFrmMain.Open1Click(Sender: TObject);
var
   HVAName : string;
begin
   if SaveFileQuery = False then Exit;

   if OpenVXLDialog.Execute then
     if LoadVoxel(OpenVXLDialog.FileName) then

   begin
     VXLFileExists := True;
     HVAName := copy(OpenVXLDialog.Filename,1,Length(OpenVXLDialog.FileName) - 3) + 'hva';
     if FileExists(HVAName) then
     begin
       try
         if not LoadHVA(HVAName) then
           ClearHVA;
       except
         end;
     end
     else
       ClearHVA;
     PostLoad;
   end;
end;

procedure TFrmMain.FormCreate(Sender: TObject);
var
  i : Integer;
  pfd : TPIXELFORMATDESCRIPTOR;
  pf  : Integer;
  r : TRect;
begin
  PaintingToolProcMouseDown[VxlTool_Pencil] := PencilToolMouseDownMove;
  PaintingToolProcMouseMove[VxlTool_Pencil] := PencilToolMouseDownMove;
  PaintingToolProcMouseUp  [VxlTool_Pencil] := PencilToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_Line] := LineToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_Line] := LineToolMouseMove;
  PaintingToolProcMouseUp  [VxlTool_Line] := LineToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_FrameRect] := LineToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FrameRect] := FrameRectToolMouseMove;
  PaintingToolProcMouseUp  [VxlTool_FrameRect] := FrameRectToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_FillRect] := LineToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FillRect] := FillRectToolMouseMove;
  PaintingToolProcMouseUp  [VxlTool_FillRect] := FillRectToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_FrameEllipse] := LineToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FrameEllipse] := FrameEllipseToolMouseMove;
  PaintingToolProcMouseUp  [VxlTool_FrameEllipse] := FrameEllipseToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_FillEllipse] := LineToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FillEllipse] := FillEllipseToolMouseMove;
  PaintingToolProcMouseUp  [VxlTool_FillEllipse] := FillEllipseToolMouseUp;
  PaintingToolProcMouseDown[VxlTool_FloodFill] := FloodFillToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FloodFill] := NullToolProc;
  PaintingToolProcMouseUp  [VxlTool_FloodFill] := NullToolProc;
  PaintingToolProcMouseDown[VxlTool_FloodFill3D] := FloodFill3DToolMouseDown;
  PaintingToolProcMouseMove[VxlTool_FloodFill3D] := NullToolProc;
  PaintingToolProcMouseUp  [VxlTool_FloodFill3D] := NullToolProc;

  ViewLabels[0] := ViewLabel0;
  ViewLabels[1] := ViewLabel1;
  ViewLabels[2] := ViewLabel2;
  ViewCanvas[0] := ViewCanvas0;
  ViewCanvas[1] := ViewCanvas1;
  ViewCanvas[2] := ViewCanvas2;
  CanvasContainers[0] := CanvasContainer0;
  CanvasContainers[1] := CanvasContainer1;
  CanvasContainers[2] := CanvasContainer2;

  Enabled3DView := True;

  vseLoadCursors;

   // HBD: Brush Shape Initializations; TODO: This is stupid - HBD
   {
   BrushShape1[0,0]:=True; BrushShape1[1,0]:=True;
   BrushShape1[0,1]:=True; BrushShape1[1,1]:=True;

   BrushShape2[0,-1]:=True;
   BrushShape2[-1,0]:=True; BrushShape2[0,0]:=True; BrushShape2[1,0]:=True;
   BrushShape2[0,1]:=True;

   BrushShape3[-1,-1]:=True; BrushShape3[0,-1]:=True; BrushShape3[1,-1]:=True;
   BrushShape3[-1,0]:=True; BrushShape3[0,0]:=True; BrushShape3[1,0]:=True;
   BrushShape3[-1,1]:=True; BrushShape3[0,1]:=True; BrushShape3[1,1]:=True;

   BrushShape4[0,-1]:=True; BrushShape4[1,-1]:=True;
   BrushShape4[-1,0]:=True; BrushShape4[0,0]:=True; BrushShape4[1,0]:=True; BrushShape4[2,0]:=True;
   BrushShape4[-1,1]:=True; BrushShape4[0,1]:=True; BrushShape4[1,1]:=True; BrushShape4[2,1]:=True;
   BrushShape4[0,2]:=True; BrushShape4[1,2]:=True;

   BrushShape5[0,-2]:=True;
   BrushShape5[-1,-1]:=True; BrushShape5[0,-1]:=True; BrushShape5[1,-1]:=True;
   BrushShape5[-2,0]:=True; BrushShape5[-1,0]:=True; BrushShape5[0,0]:=True; BrushShape5[1,0]:=True; BrushShape5[2,0]:=True;
   BrushShape5[-1,1]:=True; BrushShape5[0,1]:=True; BrushShape5[1,1]:=True;
   BrushShape5[0,2]:=True;
   }
   SetEditable(False);

   LeftPanel.DoubleBuffered := True;
   RightPanel.DoubleBuffered := True;

   cnvPalette.ControlStyle := cnvPalette.ControlStyle + [csOpaque];
   ViewCanvas0.ControlStyle := ViewCanvas0.ControlStyle + [csOpaque];
   ViewCanvas1.ControlStyle := ViewCanvas0.ControlStyle;
   ViewCanvas2.ControlStyle := ViewCanvas0.ControlStyle;

   mnuReopen := @ReOpen1;

   changecaption(false,'');

  FrmOGL3dPreview := TFrmOGL3dPreview.Create(Self);
  OGL3dPreview := FrmOGL3dPreview.OGL3DPreview;

  OGL3dPreview.OnMouseDown := OGL3dPreviewMouseDown;
  OGL3dPreview.OnMouseUp := OGL3dPreviewMouseUp;
  OGL3dPreview.OnMouseMove := OGL3dPreviewMouseMove;
  FrmOGL3DPreview.OnResize := OGL3dPreviewResize;
  FrmOGL3DPreview.OnPaint := OGL3DPreviewPaint;
  FrmOGL3DPreview.OnMouseWheelUp := OGL3DPreviewMouseWheelUp;
  FrmOGL3DPreview.OnMouseWheelDown := OGL3DPreviewMouseWheelDown;
  FrmOGL3DPreview.OnClose := OGL3DPreviewClose;
  FrmInputVector := TFrmInputVector.Create(Self);

   // OpenGL Initialization
   InitOpenGL;
   dc:=GetDC(FrmOGL3dPreview.Handle);

   BGColor   := CleanVCCol(GetPaletteColor(-1));
   FontColor := CreateVector3f(1,1,1);
   Size      := 0.2;

   RemapColor.X := RemapColorMap[0].X /255;
   RemapColor.Y := RemapColorMap[0].Y /255;
   RemapColor.Z := RemapColorMap[0].Z /255;

   // PixelFormat
   pfd.nSize:=sizeof(pfd);
   pfd.nVersion:=1;
   pfd.dwFlags:=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or 0;
   pfd.iPixelType:=PFD_TYPE_RGBA;      // PFD_TYPE_RGBA or PFD_TYPEINDEX
   pfd.cColorBits:=32;

   pf :=ChoosePixelFormat(dc, @pfd);   // Returns format that most closely matches above pixel format
   SetPixelFormat(dc, pf, @pfd);

   rc :=wglCreateContext(dc);    // Rendering Context = window-glCreateContext
   wglMakeCurrent(dc,rc);        // Make the DC (Form1) the rendering Context

   ActivateRenderingContext(DC, RC);

   glEnable(GL_TEXTURE_2D); // Enable texture mapping
   glClearColor(BGColor.X, BGColor.Y, BGColor.Z, 1.0);
   glShadeModel(GL_SMOOTH); // Enables smooth color shading
   glClearDepth(1.0);       // Depth buffer setup
   glEnable(GL_DEPTH_TEST); // Enable depth buffer
   glDepthFunc(GL_LESS);		// The type of depth test to do

   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really nice perspective calculations

   BuildFont;

   glEnable(GL_CULL_FACE);
   glCullFace(GL_BACK);

   xRot :=-90;
   yRot :=-75;
   Depth :=-30;

  glViewport(0, 0, OGL3DPreview.Width, OGL3DPreview.Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, OGL3DPreview.Width/OGL3DPreview.Height, 1.0, 500.0);
  glMatrixMode(GL_MODELVIEW);
  SetEnabled3DView(True);

  InfoForm := TFrmVectorInfo.Create(Self);
  with InfoForm do begin
    Left := 0;
    Top := 0;
    Parent := pnlInfo;
    Show;
  end;
end;

procedure TFrmMain.changecaption(Filename : boolean; FName : string);
begin
   Caption := 'Voxel Section Editor III v1.38 SE';

   if Filename then
      Caption := Caption + ' [' + extractfilename(FName) + ']';
end;

Procedure TFrmMain.SetEditable(Value : Boolean);
var
  i : integer;
begin
  Editable := value;

  if Value then
  begin
    // Associate Event Handlers
    // FrmMain.OnResize := FormResize;
    FrmMain.OnKeyDown := FormKeyDown;
    CanvasContainer0.OnResize := CanvasContainer0Resize;
    CanvasContainer1.OnResize := CanvasContainer1Resize;
    CanvasContainer2.OnResize := CanvasContainer2Resize;

  end else begin
    pnlActiveColor.Color := clBtnFace;
    lblActiveColor.Caption := '';

    // De-associate Event Handlers
    // FrmMain.OnResize := nil;
    FrmMain.OnKeyDown := nil;
    CanvasContainer0.OnResize := nil;
    CanvasContainer1.OnResize := nil;
    CanvasContainer2.OnResize := nil;

  end;

  ViewCanvas0.Visible := Value;
  ViewCanvas1.Visible := Value;
  ViewCanvas2.Visible := Value;
  // File menu
  Properties1.Enabled := Value;
  // Edit menu
  Undo1.Enabled := Value;
  Redo1.Enabled := Value;
  Copy1.Enabled := Value;
  Cut1.Enabled := Value;
  Paste1.Enabled := Value;
  PasteFull1.Enabled := Value;
  View1.Enabled := Value;
  Section1.Enabled := Value;
  Tools1.Enabled := Value;
  SaveAs1.Enabled := Value;
  Save1.Enabled := Value;


   SectionCombo.Enabled := Value;


   btnPencilTool.Enabled := Value;
   btnLineTool.Enabled := Value;
   btnRectTool.Enabled := Value;
   btnFillRectTool.Enabled := Value;
   btnEllipseTool.Enabled := Value;
   btnFillEllipseTool.Enabled := Value;
   btnFloodFillTool.Enabled := Value;
   btnFloodFill3DTool.Enabled := Value;
   btnToggleCN.Enabled := Value;
   btnNormalPenTool.Enabled := Value;

  XCursorTrackBar.Enabled := Value;
  YCursorTrackBar.Enabled := Value;
  ZCursorTrackBar.Enabled := Value;

  pnlPalette.Visible := Value;

  MainViewScrollH.Enabled := Value;
  MainViewScrollV.Enabled := Value;

   mnuDirectionPopup.AutoPopup := Value;


end;

Procedure TFrmMain.SetupSections;
var
   i : integer;
begin
   SectionCombo.Clear;

   for i := 0 to (VoxelFile.Header.NumSections - 1) do
      SectionCombo.Items.Add(VoxelFile.Section[i].Name);
   SectionCombo.ItemIndex := CurrentSection;
end;

procedure TFrmMain.SectionComboChange(Sender: TObject);
begin
   CurrentSection := SectionCombo.ItemIndex;
   ActiveSection := VoxelFile.Section[CurrentSection];
   ModelViews[0].Model := ActiveSection;
   ModelViews[1].Model := ActiveSection;
   ModelViews[2].Model := ActiveSection;
   RepaintAllViews;
end;

Procedure TFrmMain.SetSpectrum(Mode : ESpectrumMode);
begin

   if Mode = smNormals then begin
      PaintNormalPalette(cnvPalette);
   end else begin
      PaintColorPalette(cnvPalette);
   end;

   SpectrumMode := Mode;

   RebuildLists := true;

   RepaintAllViews;
end;

procedure TFrmMain.cnvPalettePaint(Sender: TObject);
begin
  if SpectrumMode = smColors then PaintColorPalette(cnvPalette)
  else PaintNormalPalette(cnvPalette);
end;

procedure TFrmMain.SetActiveColor(Index: Integer; UpdateUI: Boolean);
begin
  ActiveColor := Index;
  UpdateColorNormalInfo(Index);
  cnvPalette.Repaint;
end;

procedure TFrmMain.SetActiveNormal(Index: integer; UpdateUI: boolean);
// var
//    n : integer;
begin
   ActiveNormal := Index;

   if UpdateUI then
      if SpectrumMode = smNormals then
         UpdateColorNormalInfo(Index);

   cnvPalette.Repaint;
end;

Procedure TFrmMain.UpdateColorNormalInfo(Value : integer);
begin
   pnlActiveColor.Color := GetPaletteColor(Value);
   pnlActiveColor.repaint;
   lblActiveColor.Caption := IntToStr(Value) + ' (0x' + IntToHex(Value,2) + ')';
end;

Function GetParamStr : String;
var
x : integer;
begin
   Result := '';
   for x := 1 to ParamCount do
      if Result <> '' then
         Result := Result + ' ' +ParamStr(x)
      else
         Result := ParamStr(x);
end;

procedure TFrmMain.FormShow(Sender: TObject);
var
   VoxelName,HVAName: string;
begin

   WindowState := wsMaximized;
   VXLTool := 0;

   if ParamCount > 0 then
   begin
      VoxelName := GetParamStr;
      If FileExists(VoxelName) then
      Begin
         SetEditable(LoadVoxel(VoxelName));
         if Editable then
         begin
            HVAName := copy(VoxelName,1,Length(VoxelName) - 3) + 'hva';
            if FileExists(HVAName) then
            begin
               try
                  if not LoadHVA(HVAName) then
                     ClearHVA;
               except
               end;
            end;
            PostLoad;
         end;
      End;
   end;
end;

procedure TFrmMain.cnvPaletteMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  idx, n: Integer;
begin
  idx := ((X div 20) shl 5) + (Y shr 3);
  if SpectrumMode = smColors then
    SetActiveColor(idx,true)
  else
  begin
    if ActiveSection.Tailer.Unknown = 4 then n := NormalCountRA2
    else n := NormalCountTS;
    if idx in [0..n-1] then SetActiveNormal(idx,true);
  end;
end;

procedure BuildUsedColorsArray;
var
   x,y,z : integer;
   v : TVoxel;
begin
   for x := 0 to 255 do
   begin
      UsedColors[x] := false;
      UsedNormals[x] := false;
   end;

   for x := 0 to ActiveSection.Tailer.XSize -1 do
   for y := 0 to ActiveSection.Tailer.YSize -1 do
   for z := 0 to ActiveSection.Tailer.ZSize -1 do
   begin
      ActiveSection.GetVoxel(x,y,z,v);
      if v.Used then
      begin
         UsedColors[v.Color] := true;
         UsedNormals[v.normal] := true;
      end;
   end;
end;

procedure TFrmMain.ShowUsedColorsNormals1Click(Sender: TObject);
begin
   ShowUsedColorsNormals1.Checked := not UsedColorsOption;
   UsedColorsOption := ShowUsedColorsNormals1.Checked;
   // 1.2b: Refresh Show Use Colors
   if UsedColorsOption then
      BuildUsedColorsArray;
   if SpectrumMode = smColors then PaintColorPalette(cnvPalette)
   else PaintNormalPalette(cnvPalette);
end;

procedure TFrmMain.FormDestroy(Sender: TObject);
begin
   wglMakeCurrent(0,0);
   wglDeleteContext(rc);
end;

procedure TFrmMain.OGL3DPreviewMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
   if MouseButton = 1 then
   begin
      xRot := xRot + (Y - Ycoord)*0.5;  // moving up and down = rot around X-axis
      yRot := yRot + (X - Xcoord)*0.5;
      Xcoord := X;
      Ycoord := Y;
      Repaint3DView;
   end
   else
   if MouseButton = 2 then
   begin
      Depth := Depth - (Y-ZCoord)*0.25;
      Zcoord := Y;
      Repaint3DView;
   end;
end;

procedure TFrmMain.OGL3DPreviewMouseWheelUp(Sender: TObject;
  Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  if Depth < 0 then Depth := Depth + 1;
  Repaint3DView;
end;

procedure TFrmMain.OGL3DPreviewMouseWheelDown(Sender: TObject;
  Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  Depth := Depth - 1;
  Repaint3DView;
end;

procedure TFrmMain.OGL3DPreviewMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
   if Button = mbLeft then
   begin
      MouseButton :=1;
      Xcoord := X;
      Ycoord := Y;
   end;
   if Button = mbRight then
   begin
      MouseButton :=2;
      Zcoord := Y;
   end;
   Repaint3DView;
end;

procedure TFrmMain.OGL3DPreviewMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
   MouseButton := 0;
end;

procedure TFrmMain.SpeedButton2Click(Sender: TObject);
begin
   Depth := -30;
end;

procedure TFrmMain.BackgroundColor1Click(Sender: TObject);
begin
   ColorDialog.Color := TVector3fToTColor(BGColor);
   if ColorDialog.Execute then
      BGColor := TColorToTVector3f(ColorDialog.Color);
end;

procedure TFrmMain.TextColor1Click(Sender: TObject);
begin
   ColorDialog.Color := TVector3fToTColor(FontColor);
   if ColorDialog.Execute then
      FontColor := TColorToTVector3f(ColorDialog.Color);
end;

procedure TFrmMain.Red1Click(Sender: TObject);
begin

   Red1.Checked := true;
   RemapColor.X := RemapColorMap[0].X /255;
   RemapColor.Y := RemapColorMap[0].Y /255;
   RemapColor.Z := RemapColorMap[0].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Blue1Click(Sender: TObject);
begin
   
   Blue1.Checked := true;
   RemapColor.X := RemapColorMap[1].X /255;
   RemapColor.Y := RemapColorMap[1].Y /255;
   RemapColor.Z := RemapColorMap[1].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Green1Click(Sender: TObject);
begin
   
   Green1.Checked := true;
   RemapColor.X := RemapColorMap[2].X /255;
   RemapColor.Y := RemapColorMap[2].Y /255;
   RemapColor.Z := RemapColorMap[2].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.White1Click(Sender: TObject);
begin
   
   White1.Checked := true;
   RemapColor.X := RemapColorMap[3].X /255;
   RemapColor.Y := RemapColorMap[3].Y /255;
   RemapColor.Z := RemapColorMap[3].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Orange1Click(Sender: TObject);
begin
   
   Orange1.Checked := true;
   RemapColor.X := RemapColorMap[4].X /255;
   RemapColor.Y := RemapColorMap[4].Y /255;
   RemapColor.Z := RemapColorMap[4].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Magenta1Click(Sender: TObject);
begin
   
   Magenta1.Checked := true;
   RemapColor.X := RemapColorMap[5].X /255;
   RemapColor.Y := RemapColorMap[5].Y /255;
   RemapColor.Z := RemapColorMap[5].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Purple1Click(Sender: TObject);
begin
   
   Purple1.Checked := true;
   RemapColor.X := RemapColorMap[6].X /255;
   RemapColor.Y := RemapColorMap[6].Y /255;
   RemapColor.Z := RemapColorMap[6].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Gold1Click(Sender: TObject);
begin
   
   Gold1.Checked := true;
   RemapColor.X := RemapColorMap[7].X /255;
   RemapColor.Y := RemapColorMap[7].Y /255;
   RemapColor.Z := RemapColorMap[7].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.DarkSky1Click(Sender: TObject);
begin

   DarkSky1.Checked := true;
   RemapColor.X := RemapColorMap[8].X /255;
   RemapColor.Y := RemapColorMap[8].Y /255;
   RemapColor.Z := RemapColorMap[8].Z /255;
   RebuildLists := true;
end;

procedure TFrmMain.Front1Click(Sender: TObject);
begin
   XRot := -90;
   YRot := -90;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Back1Click(Sender: TObject);
begin
   XRot := -90;
   YRot := 90;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Left1Click(Sender: TObject);
begin
   XRot := -90;
   YRot := -180;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Right1Click(Sender: TObject);
begin
   XRot := -90;
   YRot := 0;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Bottom1Click(Sender: TObject);
begin
   XRot := 180;
   YRot := 180;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.op1Click(Sender: TObject);
begin
   XRot := 0;
   YRot := 180;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Cameo1Click(Sender: TObject);
begin
   XRot := 287;//-72.5;
   YRot := 225;//237;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Cameo21Click(Sender: TObject);
begin
   XRot := 287;//-72.5;
   YRot := 315;//302;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Cameo31Click(Sender: TObject);
begin
   XRot := 287;//-72.5;
   YRot := 255;//302;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.Cameo41Click(Sender: TObject);
begin
   XRot := 287;//-72.5;
   YRot := 285;//302;
//Depth := -30;
  Repaint3DView;
end;

procedure TFrmMain.ChangeFocus(X, Y, Z: Integer; Repaint: Boolean);
begin
  Focus.X := X;
  Focus.Y := Y;
  Focus.Z := Z;
  UpdateFocusInfo;
  if Repaint then
    Repaint2DViews;
end;

procedure TFrmMain.XCursorTrackBarChange(Sender: TObject);
begin
  Focus.X := XCursorTrackBar.Position;
  UpdateFocusInfo;

end;

Procedure TFrmMain.CursorReset;
begin
   XCursorTrackBar.Position := 0;
   YCursorTrackBar.Position := 0;
   ZCursorTrackBar.Position := 0;

   XCursorTrackBar.Max := ActiveSection.Tailer.XSize-1;
   YCursorTrackBar.Max := ActiveSection.Tailer.YSize-1;
   ZCursorTrackBar.Max := ActiveSection.Tailer.ZSize-1;

   XCursorTrackBar.Position := ActiveSection.X;
   YCursorTrackBar.Position := ActiveSection.Y;
   ZCursorTrackBar.Position := ActiveSection.Z;

   UpdateFocusInfo;
   StatusBar.Refresh;
end;

Procedure TFrmMain.SetupStatusBar;
begin
   if ActiveSection.Tailer.Unknown = 2 then
      StatusBar.Panels[0].Text := 'Game: Tiberian Sun'
   else if ActiveSection.Tailer.Unknown = 4 then
      StatusBar.Panels[0].Text := 'Game: Red Alert 2'
   else
      StatusBar.Panels[0].Text := 'Game: Unknown ' + inttostr(ActiveSection.Tailer.Unknown);

   StatusBar.Panels[1].Text := 'Length: ' + inttostr(ActiveSection.Tailer.XSize) + ', Width: ' + inttostr(ActiveSection.Tailer.YSize) + ', Height: ' + inttostr(ActiveSection.Tailer.ZSize);
   StatusBar.Panels[2].Text := '';
   StatusBar.Refresh;
end;

procedure TFrmMain.mnuEditClick(Sender: TObject);
var comp: TComponent;
begin

end;

Procedure TFrmMain.CreateVxlError(v,n : Boolean);
var
   frm : tFrmVxlError;
begin
   frm:=TFrmVxlError.Create(Self);
   frm.Visible:=False;

   frm.TabSheet1.TabVisible := v;
   frm.TabSheet2.TabVisible := n;

   frm.ShowModal;
   frm.Close;
   frm.Free;
end;

procedure TFrmMain.PostLoad;
var
  v,n : boolean;
begin
  if VXLFilename = '' then
     changecaption(true,'Untitled')
  else
     changecaption(true,VXLFilename);

  v := not IsVoxelValid;
  n := HasNormalsBug;

  if v or n then
    CreateVxlError(v,n);

  InitViews;
  AdjustViewCanvas(0);
  AdjustViewCanvas(1);
  AdjustViewCanvas(2);
  SetEditable(True);
  SetupSections;
  SetSpectrum(SpectrumMode);
  SetActiveColor(48, True);
  SetActiveNormal(0,True);
  if UsedColorsOption then
    BuildUsedColorsArray;
  SetupStatusBar;
  CursorReset;
  if SpectrumMode = smColors then PaintColorPalette(cnvPalette)
  else PaintNormalPalette(cnvPalette);
  btnPencilTool.Click;
  btnPencilTool.Down := True;
  CanvasContainers[0].Repaint;
  CanvasContainers[1].Repaint;
  CanvasContainers[2].Repaint;
  if Enabled3DView then
    FrmOGL3DPreview.Show;
end;

procedure TFrmMain.InitViews;
begin
  ModelViews[0] := TModelView.Create(ActiveSection, Focus, voTop);
  ModelViews[1] := TModelView.Create(ActiveSection, Focus, voRight);
  ModelViews[2] := TModelView.Create(ActiveSection, Focus, voBack);
  LabelPrimaryView(voTop);
  LabelSecondaryView(1, voRight);
  LabelSecondaryView(2, voBack);
  ZoomViewToFit(1);
  ZoomViewToFit(2);
  AdjustViewCanvas(0);
  AdjustViewCanvas(1);
  AdjustViewCanvas(2);
  Repaint2DViews;
end;

procedure TFrmMain.LabelPrimaryView(Orient: EModelViewOrient);
begin
  ViewLabel0.Caption := 'Editing View - ' + ViewNames[Integer(Orient)];
end;

procedure TFrmMain.LabelSecondaryView(Id: Integer; Orient: EModelViewOrient);
begin
  ViewLabels[Id].Caption := 'View - ' + ViewNames[Integer(Orient)];
end;

procedure TFrmMain.SetVXLTool(VXLToolID : Integer);
begin
  VXLTool := VXLToolID;
  ViewCanvas0.Cursor := vseCursorForTool[VxlToolID];
end;

procedure TFrmMain.btnLineToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_Line);
end;

procedure TFrmMain.btnFloodFillToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FloodFill);
end;

procedure TFrmMain.btnRectToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FrameRect);
end;

procedure TFrmMain.btnFillRectToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FillRect);
end;

procedure TFrmMain.btnEllipseToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FrameEllipse);
end;

procedure TFrmMain.btnFillEllipseToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FillEllipse);
end;

procedure TFrmMain.Save1Click(Sender: TObject);
begin
      if VXLFileExists then
      begin
         VoxelFile.SaveToFile(VXLFilename);
         VXLFileExists := True;
         Modified := false;
         changecaption(true,VXLFilename);
      end
      else
         SaveAs1Click(Sender);
end;

procedure TFrmMain.Exit1Click(Sender: TObject);
begin
  Close;
end;

procedure TFrmMain.SaveAs1Click(Sender: TObject);
begin
   if SaveVXLDialog.Execute then
   begin
      VoxelFile.SaveToFile(SaveVXLDialog.Filename);
      VXLFilename := SaveVXLDialog.Filename;
      Modified := false;
      changecaption(true,VXLFilename);
   end;
end;

procedure TFrmMain.SectionHeader1Click(Sender: TObject);
var
   FrmHeader: TFrmHeader;
begin
   FrmHeader:=TFrmHeader.Create(Self);
   with FrmHeader do
   begin
      SetValues(@VoxelFile);
      PageControl1.ActivePage := PageControl1.Pages[1];
      ShowModal;
      Free;
   end;
end;

procedure TFrmMain.Properties1Click(Sender: TObject);
var
  FrmHeader: TFrmHeader;
begin
   FrmHeader:=TFrmHeader.Create(Self);
   with FrmHeader do
   begin
      SetValues(@VoxelFile);
      PageControl1.ActivePage := PageControl1.Pages[0];
      ShowModal;
      Free;
   end;
end;

procedure TFrmMain.Delete1Click(Sender: TObject);
var
  SectionIndex,i: Integer;
begin
   if VoxelFile.Header.NumSections<2 then
   begin
      MessageDlg('Can''t delete if there''s only 1 section!',mtWarning,[mbOK],0);
      Exit;
   end;

   // ask the user to confirm
   if MessageDlg('Delete Section' +#13#13+
        'This process will delete the current section.' +#13+
        'This cannot be undone. If you choose to do this, you should first save' + #13 +
        'your model under a different name as a backup.',
        mtWarning,mbOKCancel,0) = mrCancel then
                        Exit;

   SectionIndex:=ActiveSection.Header.Number;
   VoxelFile.RemoveSection(SectionIndex);

   SectionCombo.Items.Clear;
   for i:=0 to VoxelFile.Header.NumSections-1 do
   begin
      SectionCombo.Items.Add(VoxelFile.Section[i].Name);
   end;
   SectionCombo.ItemIndex:=0;
   SectionComboChange(Self);
   Modified := true;
   RepaintAllViews;
end;

procedure TFrmMain.normalsaphere1Click(Sender: TObject);
begin
   Update3dViewWithNormals(ActiveSection);
end;

procedure TFrmMain.ClearEntireSection1Click(Sender: TObject);
begin
  if MessageDlg('Clear Entire Section' + #13#13 +
    'Are you sure?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then exit;

  ActiveSection.Clear;
  Modified := true;
  RepaintAllViews;
end;

procedure TFrmMain.VXLSEHelp1Click(Sender: TObject);
begin
   if not fileexists(extractfiledir(paramstr(0))+'/help.chm') then
   begin
      messagebox(0,'VXLSE Help' + #13#13 + 'help.chm not found','VXLSE Help',0);
      exit;
   end;
   RunAProgram('help.chm','',extractfiledir(paramstr(0)));
end;

procedure TFrmMain.Section2Click(Sender: TObject);
var
  i, SectionIndex: Integer;
  FrmNewSectionSize: TFrmNewSectionSize;
begin
   FrmNewSectionSize:=TFrmNewSectionSize.Create(Self);
   with FrmNewSectionSize do
   begin
      ShowModal;
      if aborted then Exit;
      if MessageDlg('Create Section' + #13#13+ 'Are you sure you want to create a section: ' + #13#13 +
             'Name: ' + AsciizToStr(Name,16) + Chr(10) +
             'Size: ' + IntToStr(X) + 'x' + IntToStr(Y) + 'x' + IntToStr(Z),
             mtConfirmation,[mbYes,mbNo],0) = mrNo then
         exit;

      SectionIndex:=ActiveSection.Header.Number;
      if not before then //after
         Inc(SectionIndex);


      VoxelFile.InsertSection(SectionIndex,Name,X,Y,Z);

      SectionCombo.Items.Clear;
      for i:=0 to VoxelFile.Header.NumSections-1 do
      begin
         SectionCombo.Items.Add(VoxelFile.Section[i].Name);
      end;

      VoxelFile.Section[SectionIndex].Tailer.Unknown := VoxelFile.Section[0].Tailer.Unknown;

      SectionCombo.ItemIndex:=SectionIndex;
      SectionComboChange(Self);

      Modified := true;
   end;
   FrmNewSectionSize.Free;
end;

procedure TFrmMain.Copyofthissection1Click(Sender: TObject);
var
   i, SectionIndex,x,y,z : Integer;
begin
   if MessageDlg('Copy Section' + #13#13+ 'Are you sure you want to make a copy of the current section?',
             mtConfirmation,[mbYes,mbNo],0) = mrNo then
      exit;

   SectionIndex:=ActiveSection.Header.Number;
   Inc(SectionIndex);

   VoxelFile.InsertSection(SectionIndex,'Copy Of '+VoxelFile.Section[SectionIndex-1].Name,VoxelFile.Section[SectionIndex-1].Tailer.XSize,VoxelFile.Section[SectionIndex-1].Tailer.YSize,VoxelFile.Section[SectionIndex-1].Tailer.ZSize);

   for x := 0 to (VoxelFile.Section[SectionIndex-1].Tailer.XSize - 1) do
      for y := 0 to (VoxelFile.Section[SectionIndex-1].Tailer.YSize - 1) do
         for z := 0 to (VoxelFile.Section[SectionIndex-1].Tailer.ZSize - 1) do
            VoxelFile.Section[SectionIndex].Data[x,y,z] := VoxelFile.Section[SectionIndex-1].Data[x,y,z];

   with VoxelFile.Section[SectionIndex-1].Tailer do
   begin
      VoxelFile.Section[SectionIndex].Tailer.Det := Det;
      for x := 1 to 3 do
      begin
         VoxelFile.Section[SectionIndex].Tailer.MaxBounds[x] := MaxBounds[x];
         VoxelFile.Section[SectionIndex].Tailer.MinBounds[x] := MinBounds[x];
      end;
      VoxelFile.Section[SectionIndex].Tailer.SpanDataOfs := SpanDataOfs;
      VoxelFile.Section[SectionIndex].Tailer.SpanEndOfs := SpanEndOfs;
      VoxelFile.Section[SectionIndex].Tailer.SpanStartOfs := SpanStartOfs;
      for x := 1 to 3 do
         for y := 1 to 4 do
            VoxelFile.Section[SectionIndex].Tailer.Transform[x,y] := Transform[x,y];

      VoxelFile.Section[SectionIndex].Tailer.Unknown := Unknown;
   end;

   SectionCombo.Items.Clear;
   for i:=0 to VoxelFile.Header.NumSections-1 do
   begin
      SectionCombo.Items.Add(VoxelFile.Section[i].Name);
   end;

   //MajorRepaint;
   SectionCombo.ItemIndex:=SectionIndex;
   SectionComboChange(Self);
   Modified := true;
end;

procedure TFrmMain.mnuHistoryClick(Sender: TObject);
var
   p: ^TMenuItem;
   s,VoxelName,HVAName : string;
begin
   if Sender.ClassNameIs('TMenuItem') then
   begin //check to see if it is this class
      //and now do some dirty things with pointers...
      p:=@Sender;
      if SaveFileQuery = False then Exit;

      if not fileexists(s) then
      begin
         Messagebox(0,'File Doesn''t Exist','Load Voxel',0);
         exit;
      end;

      SetEditable(LoadVoxel(VoxelName));
      if Editable then
      begin
         HVAName := copy(VoxelName,1,Length(VoxelName) - 3) + 'hva';
         if FileExists(HVAName) then
         begin
            try
               if not LoadHVA(HVAName) then
                  ClearHVA;
            except
            end;
         end
         else
            ClearHVA;
         PostLoad;
      end;
   end;
end;

procedure TFrmMain.TiberianSunPalette1Click(Sender: TObject);
begin
   LoadPaletteFromFile(ExtractFileDir(ParamStr(0)) + '\palettes\TS\unittem.pal');
   cnvPalette.Repaint;
end;

procedure TFrmMain.RedAlert2Palette1Click(Sender: TObject);
begin
   LoadPaletteFromFile(ExtractFileDir(ParamStr(0)) + '\palettes\RA2\unittem.pal');
   cnvPalette.Repaint;
end;

procedure TFrmMain.blank1Click(Sender: TObject);
begin
   LoadPaletteFromFile(PaletteList.Data[TMenuItem(Sender).tag]);
   cnvPalette.Repaint;
end;

Function TFrmMain.SaveFileQuery;
var
   T : string;
   mr: Word;
begin
  Result := True;
  if Modified then
  begin
      T := ExtractFileName(VXLFilename);
      if t = '' then
         T := 'Save Untitled'
      else
         T := 'Save changes in ' + T;

      mr := MessageDlg('Last changes not saved. ' + T +' ?',mtWarning,mbYesNoCancel,0);
      case mr of
        mrYes: Save1.Click;
        // Problem: Should return false if the user clicks Cancel
        // in the savefiledlg
        mrCancel: Result := False;
    end;
  end;
end;

procedure TFrmMain.ClearVoxelColorToolBtnClick(Sender: TObject);
var
   x,y,z : integer;
   v : tvoxel;
begin
   if MessageDlg('Clear Voxel Color' +#13#13+
        'Proceed?',
        mtWarning,mbOKCancel,0) = mrCancel then exit;

   for x := 0 to ActiveSection.Tailer.XSize-1 do
      for y := 0 to ActiveSection.Tailer.YSize-1 do
         for z := 0 to ActiveSection.Tailer.ZSize-1 do
         begin
            ActiveSection.GetVoxel(x,y,z,v);
            if SpectrumMode = smColors then
               v.Color := ActiveColor
            else
               v.Normal := ActiveNormal;
            ActiveSection.SetVoxel(x,y,z,v);
         end;
   RepaintAllViews;
   Modified := true;
end;

procedure firstlastword(const words : string; var first,rest : string);
var
   x,w : integer;
   seps : array[0..50] of string;
   endofword : boolean;
   text : string;
begin
   text := words;
   seps[0] := ' ';
   seps[1] := '(';
   seps[2] := ')';
   seps[3] := '[';
   seps[4] := #09;
   seps[5] := ']';
   seps[6] := ':';
   seps[7] := '''';
   seps[8] := '"';
   seps[9] := '=';
   seps[10] := ',';
   seps[11] := ';';
   repeat
      w := 0;
      endofword:=false;
      for x := 1 to length(text) do
         if endofword=false then
            if (copy(text,x,1) <> seps[0]) and (copy(text,x,1) <> seps[1])and (copy(text,x,1) <> seps[2]) and (copy(text,x,1) <> seps[3]) and (copy(text,x,1) <> seps[4]) and (copy(text,x,1) <> seps[5]) and (copy(text,x,1) <> seps[6]) and (copy(text,x,1) <> seps[7]) and (copy(text,x,1) <> seps[8]) and (copy(text,x,1) <> seps[9]) and (copy(text,x,1) <> seps[10]) and (copy(text,x,1) <> seps[11]) then
               w := w + 1
            else
               endofword := true;

      if w = 0 then
         text := copy(text,2,length(text));
   until (w > 0) or (length(text) = 0);
   first := copy(text,1,w);
   rest := copy(text,w+1,length(text));
end;

procedure firstlastword2(const words : string; var first,rest : string);
var
   x,w : integer;
   seps : array[0..50] of string;
   endofword : boolean;
   text : string;
begin
   text := words;
   seps[0] := #09;
   seps[1] := ';';
   seps[2] := '=';
   repeat
      w := 0;
      endofword:=false;
      for x := 1 to length(text) do
         if endofword=false then
            if (copy(text,x,1) <> seps[0]) and (copy(text,x,1) <> seps[1]) and (copy(text,x,1) <> seps[2]) then
               w := w + 1
            else
               endofword := true;

      if w = 0 then
         text := copy(text,2,length(text));
   until (w > 0) or (length(text) = 0);
   first := copy(text,1,w);
   rest := copy(text,w+1,length(text));
end;

procedure TFrmMain.VoxelTexture1Click(Sender: TObject);
var
   frm: TFrmVoxelTexture;
begin
   frm:=TFrmVoxelTexture.Create(Self);
   frm.Visible:=False;
   frm.ShowModal;
   frm.Close;
   frm.Free;
end;

procedure TFrmMain.Importfrommodel1Click(Sender: TObject);
var
   tempvxl : TVoxelModel;
   i, SectionIndex,tempsectionindex(*,u1,u2,{u3,}num*): Integer;
   frm: Tfrmimportsection;
begin
   tempvxl := TVoxelModel.Create;

   if OpenVXLDialog.execute then
   begin
      tempvxl.LoadFromFile(OpenVXLDialog.Filename);
      tempsectionindex := 0;
      if tempvxl.Header.NumSections > 1 then
      begin
         frm:=Tfrmimportsection.Create(Self);
         frm.Visible:=False;

         frm.ComboBox1.Items.Clear;
         for i:=0 to tempvxl.Header.NumSections-1 do
         begin
            frm.ComboBox1.Items.Add(tempvxl.Section[i].Name);
         end;
         frm.ComboBox1.ItemIndex:=0;
         frm.ShowModal;
         tempsectionindex := frm.ComboBox1.ItemIndex;
         frm.Free;
      end;

      SectionIndex:=ActiveSection.Header.Number;
      Inc(SectionIndex);

      VoxelFile.InsertSection(SectionIndex,tempvxl.Section[tempsectionindex].Name,tempvxl.Section[tempsectionindex].Tailer.XSize,tempvxl.Section[tempsectionindex].Tailer.YSize,tempvxl.Section[tempsectionindex].Tailer.ZSize);
      VoxelFile.Section[SectionIndex].Assign(tempvxl.Section[tempsectionindex]);

      tempvxl.Free;
      SetupSections;
      Modified := true;
   end;
end;

procedure TFrmMain.Resize1Click(Sender: TObject);
var
  Form: TFrmResizeVoxelSection;
begin
   Form := TFrmResizeVoxelSection.Create(Self);
   with Form do
   begin
      x := ActiveSection.Tailer.XSize;
      y := ActiveSection.Tailer.YSize;
      z := ActiveSection.Tailer.ZSize;
      if ShowModal <> mrOK then Exit;
      if changed then
      begin
         //Save undo information

         ActiveSection.Resize(x,y,z);
         SectionComboChange(Sender);
         Modified := true;
      end;
   end;
   Form.Free;
end;

procedure TFrmMain.YCursorSpinBtnUpClick(Sender: TObject);
begin
   YCursorTrackBar.Position := YCursorTrackBar.Position +1;
end;

procedure TFrmMain.YCursorSpinBtnDownClick(Sender: TObject);
begin
   YCursorTrackBar.Position := YCursorTrackBar.Position -1;
end;

procedure TFrmMain.ZCursorSpinBtnDownClick(Sender: TObject);
begin
   ZCursorTrackBar.Position := ZCursorTrackBar.Position -1;
end;

procedure TFrmMain.ZCursorSpinBtnUpClick(Sender: TObject);
begin
   ZCursorTrackBar.Position := ZCursorTrackBar.Position +1;
end;

procedure TFrmMain.XCursorSpinBtnDownClick(Sender: TObject);
begin
   XCursorTrackBar.Position := XCursorTrackBar.Position -1;
end;

procedure TFrmMain.XCursorSpinBtnUpClick(Sender: TObject);
begin
   XCursorTrackBar.Position := XCursorTrackBar.Position +1;
end;

procedure TFrmMain.UpdateFocusInfo;
begin
  XCursorTrackBar.Position := Focus.X;
  YCursorTrackBar.Position := Focus.Y;
  ZCursorTrackBar.Position := Focus.Z;
  StatusBar.Panels[3].Text := 'Cursor Pos: ' + inttostr(Focus.X) + ',' + inttostr(Focus.Y) + ',' + inttostr(Focus.Z);
end;

procedure TFrmMain.btnToggleCNClick(Sender: TObject);
begin
  if btnToggleCN.Down then begin
    SetSpectrum(smNormals);
    SetActiveNormal(ActiveNormal,true);
  end else begin
    SetSpectrum(smColors);
    SetActiveColor(ActiveColor,true);
  end;
end;

Function CharToStr : String;
var
x : integer;
begin
   for x := 1 to 16 do
      Result := VoxelFile.Header.FileType[x];
end;

Function CleanString(S : string) : String;
var
   x : integer;
begin
   Result := '';
   for x := 1 to Length(s) do
      if (S[x] <> '&') and (S[x] <> 'x') then
         Result := Result + S[x];
end;

procedure TFrmMain.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
  Ord('Q'): begin btnPencilTool.Click; btnPencilTool.Down := True; end;
  Ord('W'): begin btnLineTool.Click; btnLineTool.Down := True; end;
  Ord('E'): begin btnRectTool.Click; btnRectTool.Down := True; end;
  Ord('R'): begin btnFillRectTool.Click; btnFillRectTool.Down := True; end;
  Ord('D'): begin btnEllipseTool.Click; btnEllipseTool.Down := True; end;
  Ord('F'): begin btnFillEllipseTool.Click; btnFillEllipseTool.Down := True; end;
  Ord('Z'): begin btnToggleCN.Down := not btnToggleCN.Down; btnToggleCN.Click; end;
  Ord('T'): begin btnFloodFillTool.Click; btnFloodFillTool.Down := True; end;
  Ord('G'): begin btnFloodFill3DTool.Click; btnFloodFill3DTool.Down := True; end;
  end;
end;

procedure TFrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if SaveFileQuery = False then CanClose := False;
end;

procedure TFrmMain.btnPencilToolClick(Sender: TObject);
begin
  SetVxlTool(VxlTool_Pencil);
end;
(*
procedure TFrmMain.PredrawPalettes;
var
  i: Integer;
  r: TRect;
  v: TVector3f;
begin
  i := 0; r.left := 0;
  while r.left < 160 do begin
    r.top := 0;
    r.Right := r.left + 20;
    while r.top < 256 do begin
      r.Bottom := r.Top + 8;
      v.X := 128*(RA2Normals[i].X+1);
      v.Y := 128*(RA2Normals[i].Y+1);
      v.Z := 128*(RA2Normals[i].Z+1);
      with PaletteBitmapC.Canvas do begin
        Brush.Color := VxlPalette[i];
        FillRect(r);
      end;
      with PaletteBitmapN.Canvas do begin
        Brush.Color := CleanVCol(v);
        Fillrect(r);
      end;
      r.top := r.top+8;
      inc(i);
    end;
    r.left := r.left+20;
  end;
end;
*)
procedure TFrmMain.OGL3dPreviewResize(Sender: TObject);
begin
  glViewport(0, 0, OGL3DPreview.Width, OGL3DPreview.Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, OGL3DPreview.Width/OGL3DPreview.Height, 1.0, 500.0);
  glMatrixMode(GL_MODELVIEW);
end;

procedure TFrmMain.OGL3DPreviewPaint(Sender: TObject);
begin
  Repaint3DView;
end;

procedure TFrmMain.OGL3DPreviewClose(Sender: TObject; var Action: TCloseAction);
begin
  SetEnabled3DView(False);
end;

procedure TFrmMain.Repaint2DViews;
begin
  ViewCanvas0.Repaint;
  ViewCanvas1.Repaint;
  ViewCanvas2.Repaint;
end;

procedure TFrmMain.Repaint3DView;
begin
  DrawGLScene;
  SwapBuffers(DC);
end;

procedure TFrmMain.RepaintAllViews;
begin
  Repaint2DViews;
  Update3dView(ActiveSection);
  if Enabled3DView then Repaint3DView;
end;

procedure TFrmMain.btnFindNormalClick(Sender: TObject);
begin
  if FrmInputVector.ShowModal = mrOK then
    if ActiveSection.Tailer.Unknown = 4 then
      SetActiveNormal(GetNearestNormalRA2(FrmInputVector.VectorInput), True)
    else
      SetActiveNormal(GetNearestNormalTS(FrmInputVector.VectorInput), True);
end;

procedure TFrmMain.btnShowNormalInfoClick(Sender: TObject);
var
  S: String;
begin
  if ActiveSection.Tailer.Unknown = 4 then begin
    with InfoForm as TFrmVectorInfo do begin
      Str(RA2Normals[ActiveNormal].X:0:6, S);
      lblValX.Caption := S;
      Str(RA2Normals[ActiveNormal].Y:0:6, S);
      lblValY.Caption := S;
      Str(RA2Normals[ActiveNormal].Z:0:6, S);
      lblValZ.Caption := S;
    end
  end else begin
    with InfoForm as TFrmVectorInfo do begin
      Str(TSNormals[ActiveNormal].X:0:6, S);
      lblValX.Caption := S;
      Str(TSNormals[ActiveNormal].Y:0:6, S);
      lblValY.Caption := S;
      Str(TSNormals[ActiveNormal].Z:0:6, S);
      lblValZ.Caption := S;
    end
  end;
end;

procedure TFrmMain.New1Click(Sender: TObject);
var
  Form: TFrmNewVoxel;
  GameType: Integer;
begin
  if SaveFileQuery = False then Exit;

  Form := TFrmNewVoxel.Create(Self);
  with Form do
  begin
    txtX.Text := '16';
    txtY.Text := '16';
    txtZ.Text := '16';
    if ShowModal <> mrOK then Exit;
  end;

  if Form.radTibSun.Checked then GameType := 2 else GameType := 4;
  if NewVoxel(GameType, Form.InputX, Form.InputY, Form.InputZ) then
    PostLoad;
end;

procedure TFrmMain.btnFloodFill3DToolClick(Sender: TObject);
begin
  SetVXLTool(VXLTool_FloodFill3D);
end;

// TODO: Create restore point and update undo/redo state
procedure TFrmMain.RemoveredundantVoxels2Click(Sender: TObject);
var
  RemoveCount: Cardinal;
  TimeUsed: Cardinal;
begin
  if MessageDlg(
    'Remove Redundant Voxels' + #13#13 +
    'Proceed?',
    mtConfirmation, [mbYes, mbNo], 0
  ) = mrYes then
  begin
    TimeUsed := GetTickCount;
    RemoveCount := velRemoveRedundantVoxels(ActiveSection);
    TimeUsed := GetTickCount - TimeUsed;
    ShowMessage('Remove Redundant Voxels' +#13#13+ 'Removed: ' + IntToStr(RemoveCount)
      + #13 + 'Time used: ' + IntToStr(TimeUsed) + 'ms');
    RepaintAllViews;
    Modified := True;
  end;
end;

procedure TFrmMain.Enable3DView1Click(Sender: TObject);
begin
  SetEnabled3DView(not Enable3DView1.Checked);
  if Enabled3DView then
    FrmOGL3DPreview.Show
  else
    FrmOGL3DPreview.Hide;
end;

procedure TFrmMain.SetEnabled3DView(Enabled: Boolean);
begin
  Enabled3DView := Enabled;
  Enable3DView1.Checked := Enabled;
end;

procedure TFrmMain.AutoNormals11Click(Sender: TObject);
var
  TimeUsed: Cardinal;
begin
  if MessageDlg(
    'Auto Normals - Method 1' + #13#13 +
    'Proceed?',
    mtConfirmation, [mbYes, mbNo], 0
  ) = mrYes then
  begin
    TimeUsed := GetTickCount;
    velAutoNormals1(ActiveSection);
    TimeUsed := GetTickCount - TimeUsed;
    ShowMessage('Auto Normals - Method 1' + #13#13 + 'Time used: ' + IntToStr(TimeUsed) + 'ms');
    RepaintAllViews;
    Modified := True;
  end;
end;

procedure TFrmMain.ReplaceColors1Click(Sender: TObject);
var
  Form: TFrmReplaceColor;
begin
  Form := TFrmReplaceColor.Create(Self);
  Form.ShowModal;
end;

(*
procedure TFrmMain.ListNormalInfo1Click(Sender: TObject);
var
  Form: TForm;
  TextBox: TMemo;
  s1, s2, s3, s4: String;
  Lines: TStringList;
  i: Integer;
  m: Single;
begin
  Lines := TStringList.Create;
  for i:=0 to 240 do
  begin
    m := (RA2Normals[i].X*RA2Normals[i].X+RA2Normals[i].Y*RA2Normals[i].Y+RA2Normals[i].Z*RA2Normals[i].Z);
    str(RA2Normals[i].X:0:6, s1);
    str(RA2Normals[i].Y:0:6, s2);
    str(RA2Normals[i].Z:0:6, s3);
    str(m:0:6, s4);
    Lines.Append('x='+s1+', y='+s2+', z='+s3+' M^2='+s4);
  end;
  Form := TForm.Create(Self);
  TextBox := TMemo.Create(Form);
  TextBox.Align := alClient;
  TextBox.Parent := Form;
  TextBox.ScrollBars := ssVertical;
  TextBox.Lines := Lines;
  Form.ShowModal;
end;
*)

procedure TFrmMain.ViewCanvas0Paint(Sender: TObject);
begin
  with ModelViews[0] do
  begin
    Paint;
    Blit(ViewCanvas0.Canvas);
  end;
end;

procedure TFrmMain.ViewCanvas1Paint(Sender: TObject);
begin
  with ModelViews[1] do
  begin
    Paint;
    HighlightFocus;
    Blit(ViewCanvas1.Canvas);
  end;
end;

procedure TFrmMain.ViewCanvas2Paint(Sender: TObject);
begin
  with ModelViews[2] do
  begin
    Paint;
    HighlightFocus;
    Blit(ViewCanvas2.Canvas);
  end;
end;

procedure TFrmMain.AdjustViewCanvas(Id: Integer);
begin
  ViewCanvas[Id].Left := (CanvasContainers[Id].Width - ModelViews[Id].WidthOnScreen) shr 1;
  ViewCanvas[Id].Top := (CanvasContainers[Id].Height - ModelViews[Id].HeightOnScreen) shr 1;
  ViewCanvas[Id].Width := ModelViews[Id].WidthOnScreen;
  ViewCanvas[Id].Height := ModelViews[Id].HeightOnScreen;
end;

procedure TFrmMain.ZoomEditingViewToFit1Click(Sender: TObject);
begin
  ZoomViewToFit(0);
end;

procedure TFrmMain.ZoomViewToFit(Id: Integer);
var
  magx, magy: Integer;
begin
  magx := CanvasContainers[Id].Width div ModelViews[Id].Width;
  magy := CanvasContainers[Id].Height div ModelViews[Id].Height;
  ModelViews[Id].Zoom := Min(magx, magy);
  AdjustViewCanvas(Id);
end;

procedure TFrmMain.ViewLabel1Click(Sender: TObject);
var
  o: EModelViewOrient;
begin
  o := ModelViews[1].Orient;
  ModelViews[1].ChangeOrient(ModelViews[0].Orient);
  LabelSecondaryView(1, ModelViews[0].Orient);
  ModelViews[0].ChangeOrient(o);
  LabelPrimaryView(o);
  ZoomViewToFit(1);
  AdjustViewCanvas(0);
  AdjustViewCanvas(1);
  ViewCanvas0.Repaint;
  ViewCanvas1.Repaint;
end;

procedure TFrmMain.ViewLabel2Click(Sender: TObject);
var
  o: EModelViewOrient;
begin
  o := ModelViews[2].Orient;
  ModelViews[2].ChangeOrient(ModelViews[0].Orient);
  LabelSecondaryView(2, ModelViews[0].Orient);
  ModelViews[0].ChangeOrient(o);
  LabelPrimaryView(o);
  ZoomViewToFit(2);
  AdjustViewCanvas(0);
  AdjustViewCanvas(2);
  ViewCanvas0.Repaint;
  ViewCanvas1.Repaint;
end;

procedure TFrmMain.CrossSection1Click(Sender: TObject);
begin
  ModelViews[0].Mode := vmCrossSection;
  CrossSection1.Checked := True;
  ViewCanvas0.Repaint;
end;

procedure TFrmMain.EmphasiseDepth1Click(Sender: TObject);
begin
  ModelViews[0].Mode := vmEmphasiseDepth;
  EmphasiseDepth1.Checked := True;
  ViewCanvas0.Repaint;
end;

procedure TFrmMain.PaintPointView(X, Y: Integer);
begin
  ModelViews[0].OverlayCell(X, Y, VxlPalette[ActiveColor]);
end;

procedure TFrmMain.ClearPointView(X, Y: Integer);
begin
  ModelViews[0].OverlayCell(X, Y, BGViewColor);
end;

procedure TFrmMain.RepaintPointView(X, Y: Integer);
begin
  ModelViews[0].PaintCell(X, Y);
end;

procedure TFrmMain.PaintPointModel(X, Y: Integer);
var
  c: TVector3i;
begin
  ModelViews[0].TranslateCoord2D(X, Y, c);
  with ActiveSection.Data[c.X,c.Y,c.Z] do
  begin
    Color := ActiveColor;
    Used := True;
  end;
end;

procedure TFrmMain.ClearPointModel(X, Y: Integer);
var
  c: TVector3i;
begin
  ModelViews[0].TranslateCoord2D(X, Y, c);
  ActiveSection.Data[c.X,c.Y,c.Z].Used := False;
end;

procedure TFrmMain.NullToolProc;
begin end;

procedure TFrmMain.PencilToolMouseDownMove(X, Y: Integer);
var
  c: TVector3i;
  v: TVoxel;
begin
  if MouseDownLeft then
  begin
    ModelViews[0].TranslateCoord2D(X, Y, c);
    ActiveSection.GetVoxel(c.X, c.Y, c.Z, v);
    if SpectrumMode = smColors then
      v.Color := ActiveColor
    else
      v.Normal := ActiveNormal;
    v.Used := True;
    ActiveSection.SetVoxel(c.X, c.Y, c.Z, v);
    ModelViews[0].PaintCell(X, Y);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
    Modified := True;
  end
  else if MouseDownRight then
  begin
    ModelViews[0].TranslateCoord2D(X, Y, c);
    ActiveSection.GetVoxel(c.X, c.Y, c.Z, v);
    v.Used := False;
    ActiveSection.SetVoxel(c.X, c.Y, c.Z, v);
    ModelViews[0].OverlayCell(X, Y, BGViewColor);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
    Modified := True;
  end;
end;

procedure TFrmMain.DrawLine(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
var
  i, j, dx, dy, step: Integer;
begin
  i := X1;
  j := Y1;
  dx := X2-i;
  dy := Y2-j;
  if abs(dx) >= abs(dy) then
  begin
    if dx >= 0 then step := 1
    else step := -1;
    while True do
    begin
      // (y-y1)(x2-x1) = (x-x1)(y2-y1)
      j := Round((i-X2)*dy / dx)+Y2;
      PointProc(i, j);
      if i = X2 then break;
      i := i + step;
    end;
  end
  else
  begin
    if dy >= 0 then step := 1
    else step := -1;
    while True do
  begin
      // (y-y1)(x2-x1) = (x-x1)(y2-y1)
      i := Round((j-Y2)*dx / dy)+X2;
      PointProc(i, j);
      if j = Y2 then break;
      j := j + step;
    end;
  end;
end;

procedure TFrmMain.DrawFrameRect(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
var
  i, j, si, sj: Integer;
begin
  i := X1;
  j := Y1;
  if X2 >= i then si := 1
  else si := -1;
  if Y2 >= j then sj := 1
  else sj := -1;
  while True do
  begin
    PointProc(i, Y1);
    PointProc(i, Y2);
    if i = X2 then break;
    Inc(i, si);
  end;
  while True do
  begin
    PointProc(X1, j);
    PointProc(X2, j);
    if j = Y2 then break;
    Inc(j, sj);
  end;
end;

procedure TFrmMain.DrawFilledRect(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
var
  i, j, si, sj: Integer;
begin
  if X2 >= X1 then si := 1
  else si := -1;
  if Y2 >= Y1 then sj := 1
  else sj := -1;
  i := X1;
  while True do
  begin
    j := Y1;
    while True do
    begin
      PointProc(i, j);
      if j = Y2 then break;
      Inc(j, sj);
    end;
    if i = X2 then break;
    Inc(i, si);
  end;
end;

procedure TFrmMain.DrawFrameEllipse(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
var
  i, j, dx, dy, step: Integer;
  a, b, cx, cy: Single;
begin
  dx := X2-X1;
  dy := Y2-Y1;
  if (dx = 0) or (dy = 0) then
  begin
    DrawLine(X1, Y1, X2, Y2, PointProc); // Avoid division-by-zero errors
    Exit;
  end;
  cx := (X1+X2)/2;
  cy := (Y1+Y2)/2;
  a := abs(dx/2);
  b := abs(dy/2);
  begin
    i := X1;
    step := Sign(dx);
    while True do
    begin
      j := Round(sqrt(b*b*(a*a-(i-cx)*(i-cx))/(a*a))+cy);
      PointProc(i, j);
      j := Y1+Y2-j;
      PointProc(i, j);
      if i = X2 then break;
      i := i + step;
    end;
  end;
  begin
    j := Y1;
    step := Sign(dy);
    while True do
    begin
      i := Round(sqrt(a*a*(b*b-(j-cy)*(j-cy))/(b*b))+cx);
      PointProc(i, j);
      i := X1+X2-i;
      PointProc(i, j);
      if j = Y2 then break;
      j := j + step;
    end;
  end;
end;

procedure TFrmMain.DrawFilledEllipse(X1, Y1, X2, Y2: Integer; PointProc: TPointProc);
var
  i, j, dx, dy, step, m: Integer;
  a, b, cx, cy: Single;
begin
  dx := X2-X1;
  dy := Y2-Y1;
  if (dx = 0) or (dy = 0) then
  begin
    DrawLine(X1, Y1, X2, Y2, PointProc); // Avoid division-by-zero errors
    Exit;
  end;
  cx := (X1+X2)/2;
  cy := (Y1+Y2)/2;
  a := abs(dx/2);
  b := abs(dy/2);
  begin
    i := X1;
    step := Sign(dx);
    while True do
    begin
      j := Round(sqrt(b*b*(a*a-(i-cx)*(i-cx))/(a*a))+cy);
      m := Y1+Y2-j;
      if j < m then begin j := j xor m; m := j xor m; j := j xor m; end;
      while j>=m do
      begin
        PointProc(i, j);
        Dec(j);
      end;
      if i = X2 then break;
      i := i + step;
    end;
  end;
  begin
    j := Y1;
    step := Sign(dy);
    while True do
    begin
      i := Round(sqrt(a*a*(b*b-(j-cy)*(j-cy))/(b*b))+cx);
      PointProc(i, j);
      i := X1+X2-i;
      PointProc(i, j);
      if j = Y2 then break;
      j := j + step;
    end;
  end;
end;

procedure TFrmMain.LineToolMouseDown(X, Y: Integer);
begin
  LastViewCoords[1].X := X;
  LastViewCoords[1].Y := Y;
end;

procedure TFrmMain.LineToolMouseMove(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
  else if MouseDownRight then
  begin
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
end;

procedure TFrmMain.LineToolMouseUp(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointModel);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    DrawLine(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointModel);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.PencilToolMouseUp(X, Y: Integer);
begin
  RepaintAllViews;
end;

procedure TFrmMain.FrameRectToolMouseMove(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
  else if MouseDownRight then
  begin
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end;
end;

procedure TFrmMain.FrameRectToolMouseUp(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointModel);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    DrawFrameRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointModel);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.FillRectToolMouseMove(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
  else if MouseDownRight then
  begin
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end;
end;

procedure TFrmMain.FillRectToolMouseUp(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointModel);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    DrawFilledRect(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointModel);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.FrameEllipseToolMouseMove(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
  else if MouseDownRight then
  begin
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end;
end;

procedure TFrmMain.FrameEllipseToolMouseUp(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointModel);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    DrawFrameEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointModel);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.FillEllipseToolMouseMove(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end
  else if MouseDownRight then
  begin
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, LastViewCoords[0].X, LastViewCoords[0].Y, RepaintPointView);
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointView);
    ModelViews[0].Blit(ViewCanvas0.Canvas);
  end;
end;

procedure TFrmMain.FillEllipseToolMouseUp(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, PaintPointModel);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    DrawFilledEllipse(LastViewCoords[1].X, LastViewCoords[1].Y, X, Y, ClearPointModel);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.FloodFillToolMouseDown(X, Y: Integer);
begin
  if MouseDownLeft then
  begin
    velFloodFill2D(ActiveSection, X, Y, ActiveColor, ModelViews[0]);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    velFloodFillClear2D(ActiveSection, X, Y, ModelViews[0]);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.FloodFill3DToolMouseDown(X, Y: Integer);
var
  c: TVector3i;
begin
  if MouseDownLeft then
  begin
    ModelViews[0].TranslateCoord2D(X, Y, c);
    velFloodFill3D(ActiveSection, c.X, c.Y, c.Z, ActiveColor);
    Modified := True;
    RepaintAllViews;
  end
  else if MouseDownRight then
  begin
    ModelViews[0].TranslateCoord2D(X, Y, c);
    velFloodFillClear3D(ActiveSection, c.X, c.Y, c.Z);
    Modified := True;
    RepaintAllViews;
  end;
end;

procedure TFrmMain.ViewCanvas0MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  xt, yt: Integer;
begin
  if Button = mbLeft then
  begin
    if MouseDownRight then Exit;
    MouseDownLeft := True;
  end
  else if Button = mbRight then
  begin
    if MouseDownLeft then Exit;
    MouseDownRight := True;
  end;
  xt := X div ModelViews[0].Zoom;
  yt := Y div ModelViews[0].Zoom;
  PaintingToolProcMouseDown[VxlTool](xt, yt);
end;

procedure TFrmMain.ViewCanvas0MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  xt, yt: Integer;
begin
  xt := X div ModelViews[0].Zoom;
  yt := Y div ModelViews[0].Zoom;
  if xt < 0 then xt := 0
  else if xt >= ModelViews[0].Width then xt := ModelViews[0].Width-1;
  if yt < 0 then yt := 0
  else if yt >= ModelViews[0].Height then yt := ModelViews[0].Height-1;
  PaintingToolProcMouseMove[VxlTool](xt, yt);
  LastViewCoords[0].X := xt;
  LastViewCoords[0].Y := yt;
end;

procedure TFrmMain.ViewCanvas0MouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  xt, yt: Integer;
begin
  xt := X div ModelViews[0].Zoom;
  yt := Y div ModelViews[0].Zoom;
  if xt < 0 then xt := 0
  else if xt >= ModelViews[0].Width then xt := ModelViews[0].Width-1;
  if yt < 0 then yt := 0
  else if yt >= ModelViews[0].Height then yt := ModelViews[0].Height-1;
  PaintingToolProcMouseUp[VxlTool](xt, yt);
  if Button = mbLeft then MouseDownLeft := False
  else if Button = mbRight then MouseDownRight := False;
end;

procedure TFrmMain.BackgroundColor2Click(Sender: TObject);
begin
  ColorDialog.Color := BGViewColor;
  if ColorDialog.Execute then
  begin
    BGViewColor := ColorDialog.Color;
    Repaint2DViews;
  end;
end;

procedure TFrmMain.ViewCanvas1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  tx, ty: Integer;
  c: TVector3i;
begin
  if Button = mbLeft then
  begin
    tx := X div ModelViews[1].Zoom;
    ty := Y div ModelViews[1].Zoom;
    ModelViews[1].TranslateCoord2D(tx, ty, c);
    ChangeFocus(c.X, c.Y, c.Z, True);
  end;
end;

procedure TFrmMain.ViewCanvas2MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  tx, ty: Integer;
  c: TVector3i;
begin
  if Button = mbLeft then
  begin
    tx := X div ModelViews[2].Zoom;
    ty := Y div ModelViews[2].Zoom;
    ModelViews[2].TranslateCoord2D(tx, ty, c);
    ChangeFocus(c.X, c.Y, c.Z, True);
  end;
end;

procedure TFrmMain.ViewCanvas1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  tx, ty: Integer;
  c: TVector3i;
begin
  if ssLeft in Shift then
  begin
    tx := X div ModelViews[1].Zoom;
    ty := Y div ModelViews[1].Zoom;
    if tx < 0 then tx := 0 else if tx >= ModelViews[1].Width  then tx := ModelViews[1].Width -1;
    if ty < 0 then ty := 0 else if ty >= ModelViews[1].Height then ty := ModelViews[1].Height-1;
    ModelViews[1].TranslateCoord2D(tx, ty, c);
    ChangeFocus(c.X, c.Y, c.Z, True);
  end;
end;

procedure TFrmMain.ViewCanvas2MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  tx, ty: Integer;
  c: TVector3i;
begin
  if ssLeft in Shift then
  begin
    tx := X div ModelViews[2].Zoom;
    ty := Y div ModelViews[2].Zoom;
    if tx < 0 then tx := 0 else if tx >= ModelViews[2].Width  then tx := ModelViews[2].Width -1;
    if ty < 0 then ty := 0 else if ty >= ModelViews[2].Height then ty := ModelViews[2].Height-1;
    ModelViews[2].TranslateCoord2D(tx, ty, c);
    ChangeFocus(c.X, c.Y, c.Z, True);
  end;
end;

procedure TFrmMain.CanvasContainer1Resize(Sender: TObject);
begin
  ZoomViewToFit(1);
  AdjustViewCanvas(1);
end;

procedure TFrmMain.CanvasContainer2Resize(Sender: TObject);
begin
  ZoomViewToFit(2);
  AdjustViewCanvas(2);
end;

procedure TFrmMain.CanvasContainer0Resize(Sender: TObject);
begin
  AdjustViewCanvas(0);
end;

end.
